﻿using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.Table;
using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wams.Admin
{   
    public static class WamsInstances
    {
        public static WamsSiteState GetSiteState(CloudStorageAccount cloudAccount, string containerName, string deploymentInstanceId, int siteId)
        {
            CloudTableClient tableClient = cloudAccount.CreateCloudTableClient();

            // Create the CloudTable object that represents the "people" table.
            CloudTable table = tableClient.GetTableReference(containerName + "sites");
            if (!table.Exists()) return null;

            // Create a retrieve operation that takes a customer entity.
            TableOperation retrieveOperation = TableOperation.Retrieve<WamsSiteStateEntity>(deploymentInstanceId, siteId.ToString());

            // Execute the retrieve operation.
            TableResult retrievedResult = table.Execute(retrieveOperation);
            if (retrievedResult.Result == null) return null;

            if (DateTime.UtcNow.Subtract(((WamsSiteStateEntity)retrievedResult.Result).Timestamp.DateTime).TotalMinutes > 5) return null;
            if (DateTime.UtcNow.Subtract(((WamsSiteStateEntity)retrievedResult.Result).Timestamp.DateTime).TotalMinutes > 2) ((WamsSiteStateEntity)retrievedResult.Result).InnerStatus = (int)SiteStatus.Stale;

            return new WamsSiteState()
            {
                Id = ((WamsSiteStateEntity)retrievedResult.Result).Id,
                Status = ((WamsSiteStateEntity)retrievedResult.Result).Status,
                DeploymentInstanceId = ((WamsSiteStateEntity)retrievedResult.Result).DeploymentInstanceId
            };
        }

        public static bool OverrideInstanceStatus(string containerName, CloudStorageAccount cloudAccount, string deploymentId, int instanceId, InstanceStatus newStatus)
        {
            try
            {
                CloudTableClient tableClient = cloudAccount.CreateCloudTableClient();
                CloudTable table = tableClient.GetTableReference(containerName + "instances");

                TableOperation retrieveOperation = TableOperation.Retrieve<WamsInstanceStateEntity>(deploymentId, instanceId.ToString());

                TableResult retrievedResult = table.Execute(retrieveOperation);

                WamsInstanceStateEntity specificEntity = (WamsInstanceStateEntity)retrievedResult.Result;
                if (specificEntity == null) return false;

                specificEntity.InnerStatus = (int)newStatus;
                specificEntity.ETag = "*";
                table.Execute(TableOperation.Replace(specificEntity));
                return true;
            }
            catch { return false; }
        }

        public static bool OverrideSiteStateStatus(string containerName, CloudStorageAccount cloudAccount, string deploymentId, int instanceId, int siteId, SiteStatus newStatus)
        {
            try
            {
                CloudTableClient tableClient = cloudAccount.CreateCloudTableClient();
                CloudTable table = tableClient.GetTableReference(containerName + "sites");

                TableOperation retrieveOperation = TableOperation.Retrieve<WamsSiteStateEntity>(string.Format("{0}_{1}", deploymentId, instanceId), siteId.ToString());

                TableResult retrievedResult = table.Execute(retrieveOperation);

                WamsSiteStateEntity specificEntity = (WamsSiteStateEntity)retrievedResult.Result;
                if (specificEntity == null) return false;

                specificEntity.InnerStatus = (int)newStatus;
                specificEntity.ETag = "*";
                table.Execute(TableOperation.Replace(specificEntity));
                return true;
            }
            catch { return false; }
        }

        public static List<WamsInstanceState> GetAllInstances(string containerName, CloudStorageAccount cloudAccount)
        {
            List<WamsInstanceState> instances = new List<WamsInstanceState>();

            CloudTableClient tableClient = cloudAccount.CreateCloudTableClient();

            CloudTable table = tableClient.GetTableReference(containerName + "instances");
            if (!table.Exists()) return instances;

            TableQuery<WamsInstanceStateEntity> rangeQuery = new TableQuery<WamsInstanceStateEntity>();

            var res = table.ExecuteQuery(rangeQuery).OrderBy(x=> x.DeploymentId);

            foreach (WamsInstanceStateEntity state in res)
            {
                if (DateTime.UtcNow.Subtract(state.Timestamp.DateTime).TotalMinutes > 5) continue;
                if (DateTime.UtcNow.Subtract(state.Timestamp.DateTime).TotalMinutes > 2) state.InnerStatus = (int)InstanceStatus.Stale;
                instances.Add(new WamsInstanceState()
                {
                    InstanceId = state.InstanceId,
                    DeploymentId = state.DeploymentId,
                    IsBusy = state.IsBusy,
                    LastTimespan = state.Timestamp,
                    Status = state.Status
                });
            }

            return instances;
        }

        
        /// <summary>
        /// Installs a wams content folder from an archive.
        /// </summary>
        /// <param name="cloudStorageAccount">The cloud storage account to use</param>
        /// <param name="containerName">The cloud container name where to install the content folder</param>
        /// <param name="contentName">The name of the folder</param>
        /// <param name="stream">A stream which contains a Zip archive</param>
        public static void InstallContent(CloudStorageAccount cloudStorageAccount, string containerName, string contentName, System.IO.Stream stream)
        {
            CloudBlobContainer blobContainer = cloudStorageAccount.CreateCloudBlobClient().GetContainerReference(containerName);

            using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read))
            {
                foreach (ZipArchiveEntry entry in archive.Entries)
                {
                    if (entry.Name == "") continue;
                    CloudBlockBlob blob = blobContainer.GetBlockBlobReference(contentName + "/" + entry.FullName.Replace("\\", "/"));
                    blob.UploadFromStream(entry.Open());
                }
            }
        }
    }
}
